package gweb

import (
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"net/http"
	"regexp"
)

func loadMiddleware() {
	if viper.GetBool("httpRefererCheck.enable") {
		// 排除要检测的URL的path路径，区分大小写
		RegistryMiddleware(httpRefererCheck(viper.GetStringSlice("httpRefererCheck.excludeCheckPath"), viper.GetStringSlice("httpRefererCheck.allowedReferer")))
	}
	if viper.GetBool("allowCrossDomain") {
		RegistryMiddleware(allowCrossDomain())
	}
	if viper.GetBool("tokenCheck.enable") {
		// 排除要检测的URL的path路径，区分大小写
		RegistryMiddleware(tokenCheck(viper.GetStringSlice("tokenCheck.excludeCheckPath"),
			viper.GetString("tokenCheck.prefix"),
			viper.GetInt64("tokenCheck.updateTokenExpireSecond"),
			viper.GetStringMapString("tokenCheck.testToken"),
		))
	}
}

// AllowCrossDomain 跨域中间件
func allowCrossDomain() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
		c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
		c.Header("Access-Control-Allow-Credentials", "true")
		//放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}
		// 处理请求
		c.Next()
	}
}

// TokenCheck 检查token
// excludePath 排除要检测的URL的path路径，区分大小写, 支持正则表达式
// prefix 区分模块用的
func tokenCheck(excludePath []string, prefix string, updateTokenExpireSecond int64, testToken map[string]string) gin.HandlerFunc {
	return func(c *gin.Context) {
		if len(excludePath) > 0 && inPath(c.Request.URL.Path, excludePath) {
			c.Next()
			return
		}

		accessToken := c.Query("access_token")
		if accessToken == "" {
			Json(c, 1000, "access_token is miss", nil)
			c.Abort()
			return
		}

		// 判断是否测试token
		if v, ok := testToken[accessToken]; ok {
			c.Set("bindArg", v)
			c.Next()
			return
		}

		// 走缓存查询
		//token := NewToken(prefix)
		//bindArg := token.GetBindArgByToken(accessToken)
		//if bindArg == "" {
		//	Json(c, JsonAuthFailCode, "access_token is invalid", nil)
		//	c.Abort()
		//	return
		//}
		//c.Set("bindArg", bindArg)
		//if updateTokenExpireSecond > 0 {
		//	token.UpdateBindArgByToken(accessToken, bindArg, updateTokenExpireSecond)
		//}
		c.Next()
	}
}

// inPath
func inPath(currentPath string, excludePath []string) bool {
	for _, v := range excludePath {
		exist, _ := regexp.MatchString(v, currentPath)
		if exist {
			return true
		}
	}
	return false
}

// httpRefererCheck 检查Referer是否合法
// excludePath 排除要检测的URL的path路径，区分大小写, 支持正则表达式
// allowedReferer 允许的referer
func httpRefererCheck(excludePath []string, allowedReferer []string) gin.HandlerFunc {
	return func(c *gin.Context) {
		if len(excludePath) > 0 && inPath(c.Request.URL.Path, excludePath) {
			c.Next()
			return
		}
		referer := c.GetHeader("Referer")
		if inPath(referer, allowedReferer) {
			c.Next()
			return
		}
		Json(c, 1, "referer is invalid, please check again", nil)
		c.Abort()
		return

	}
}
